package com.siwei.infoextract.wrapper;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.siwei.infoextract.wrapper.attributeextract.AddressAttributeExtractor;
import com.siwei.infoextract.wrapper.attributeextract.PhoneAttributeExtractor;
import com.siwei.infoextract.wrapper.attributeextract.TitleAttributeExtractor;
import com.siwei.infoextract.wrapper.featureextract.InnerTextFeatureExtractor;
import com.siwei.infoextract.wrapper.parser.DomNode;
import com.siwei.infoextract.wrapper.parser.DomNodeIteratorCallback;
import com.siwei.infoextract.wrapper.parser.DomTreeTraversal;

public class InfoBlocksExtractor {
	private static final String PHONE_LEVEL = "PHONE.LEVEL";
	private static final String ADDRESS_LEVEL = "ADDRESS.LEVEL";
	private static final String TITLE_LEVEL = "TITLE.LEVEL";

	public static final float EXTRACT_THRESHOLD = (float)0.4;
	public static final float WEIGHT_TITLE = (float)0.6;
	public static final float WEIGHT_ADDRESS = (float)0.3;
	public static final float WEIGHT_PHONE = (float)0.1;

	AddressAttributeExtractor addressExtractor = new AddressAttributeExtractor();
	PhoneAttributeExtractor phoneExtractor = new PhoneAttributeExtractor();
	TitleAttributeExtractor titleExtractor = new TitleAttributeExtractor();

	public List<DomNode> extract(DomNode domNode) throws IOException {
		List<DomNode> addressNodes = addressExtractor.extract(domNode);
		List<DomNode> phoneNodes = phoneExtractor.extract(domNode);
		List<DomNode> titleNodes = titleExtractor.extract(domNode);

		for (Iterator<DomNode> iter = addressNodes.iterator(); iter.hasNext();) {
			markToRoot(iter.next(), ADDRESS_LEVEL);
		}

		for (Iterator<DomNode> iter = phoneNodes.iterator(); iter.hasNext();) {
			markToRoot(iter.next(), PHONE_LEVEL);
		}

		for (Iterator<DomNode> iter = titleNodes.iterator(); iter.hasNext();) {
			markToRoot(iter.next(), TITLE_LEVEL);
		}

		DomTreeTraversal traversal = new DomTreeTraversal(domNode); 
		
		final List<DomNode> resultList = new ArrayList<DomNode>();
		traversal.addCallback(new DomNodeIteratorCallback(){
			public void call(DomNode domNode) {
				Map<String, String> map = (Map<String, String>)domNode.getFlag();

				float score = 0;

				if (map.containsKey(TITLE_LEVEL) && map.containsKey(ADDRESS_LEVEL) && map.containsKey(PHONE_LEVEL)) {
					score = (float)1.0;
				} else if (map.containsKey(TITLE_LEVEL) && map.containsKey(ADDRESS_LEVEL)) {
					score = (float)0.8;
				} else if (map.containsKey(TITLE_LEVEL) && map.containsKey(PHONE_LEVEL)) {
					score = (float)0.6;
				} else if (map.containsKey(ADDRESS_LEVEL) && map.containsKey(PHONE_LEVEL)) {
					score = (float)0.3;
				} else if (map.containsKey(TITLE_LEVEL)) {
					score = (float)0.1;
				} else if (map.containsKey(ADDRESS_LEVEL)) {
					score = (float)0.05;
				} else if (map.containsKey(PHONE_LEVEL)) {
					score = (float)0.05;
				} else {
					score = 0;
				}

				float averageLevel = 0;
				float sumLevel = 0;
				int count = 0;
				if (map.containsKey(TITLE_LEVEL)) {
					sumLevel += Float.parseFloat(map.get(TITLE_LEVEL));
					count += 1;
				}
				if (map.containsKey(ADDRESS_LEVEL)) {
					sumLevel += Float.parseFloat(map.get(ADDRESS_LEVEL));
					count += 1;
				}
				if (map.containsKey(PHONE_LEVEL)) {
					sumLevel += Float.parseFloat(map.get(PHONE_LEVEL));
					count += 1;
				}

				if (count == 0) {
					averageLevel = (float)1.0;
				} else {
					averageLevel = sumLevel / count;
				}
				
				score /= averageLevel;
				
				if (score > EXTRACT_THRESHOLD) {
					resultList.add(domNode);
				}
			}
		});
		traversal.traverse();		

		return resultList;
	}

	private void markToRoot(DomNode tempNode, String name) {
		int i = 1;

		DomNode parentNode = null;
		if (tempNode != null) {
			parentNode = tempNode.getParent();
		}

		while(parentNode != null) {
			Map<String, String> map = null;
			if (parentNode.getFlag() != null) {
				map = (Map<String, String>)parentNode.getFlag();
			} else {
				parentNode.setFlag(new HashMap<String, String>());
			}

			float levelScore = i;
			if (map.containsKey(name)) {
				levelScore = levelScore * (float)0.5 + Float.parseFloat((String)map.get(name));
			}

			map.put(name, Float.toString(levelScore));

			i++;
			parentNode = parentNode.getParent();
		}
	}
	
	
}
